package com.taobao.apiclient.guide;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.commons.httpclient.NameValuePair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.taobao.api.ApiException;
import com.taobao.api.AutoRetryTaobaoClient;
import com.taobao.api.Constants;
import com.taobao.api.DefaultTaobaoClient;
import com.taobao.api.TaobaoClient;
import com.taobao.api.TaobaoRequest;
import com.taobao.api.TaobaoResponse;
import com.taobao.api.internal.util.WebUtils;
import com.taobao.api.request.ItemGetRequest;
import com.taobao.api.response.ItemGetResponse;
import com.taobao.apiclient.APP;
import com.taobao.apiclient.ClientUrlParams;
import com.taobao.apiclient.exception.ApiClientException;
import com.taobao.tbapi.ApiConfigs;

public class DefaultApiGuideClient {
  final static Logger          log                    = LoggerFactory.getLogger(DefaultApiGuideClient.class);

  public static String         REMOTE_URL             = "http://api.ciaosir.com/api.json";
  public static String         LOCAL_URL              = "http://www.woyaolai.com/api.json";
  public static String         LOCAL_URL2             = "http://www.woyaolai.com/api.json";
  private String               serverUrl;
  private String               registerUrl;
  private int                  connectTimeout         = 500;
  private int                  readTimeout            = 10000;

  private static AtomicInteger servelDeadNums         = new AtomicInteger(0);
  private static int           SERVEL_DEAD_NUM_LIMIT  = 20;
  private static boolean       serverDead             = false;
  private static long          servelDeadTime         = 0;
  private static long          SERVEL_DEAD_TIME_LIMIT = 180 * 1000l;

  public DefaultApiGuideClient() {

  }

  public DefaultApiGuideClient(String serverUrl, String registerUrl) {
    super();
    this.serverUrl = serverUrl;
    this.registerUrl = registerUrl;
  }

  public DefaultApiGuideClient(String serverUrl) {
    super();
    this.serverUrl = serverUrl;
    convertResiterUrl(this.serverUrl);
  }

  private void convertResiterUrl(String serverUrl) {
    if (this.registerUrl == null) {
      String host = serverUrl.substring(0, serverUrl.lastIndexOf("/"));
      this.registerUrl = host + "/updateUser.json";
    }
  }

  public DefaultApiGuideClient(String serverUrl, int connectTimeout, int readTimeout) {
    super();
    this.serverUrl = serverUrl;
    convertResiterUrl(this.serverUrl);
    this.connectTimeout = connectTimeout;
    this.readTimeout = readTimeout;
  }

  public <T extends TaobaoResponse> T execute(TaobaoRequest<T> request, Long userId, String sessionKey) throws ApiClientException {
    APP app = APP.HD;
    convertServerDeadInfo();
    if (serverDead && this.serverUrl.equals(REMOTE_URL)) {
      try {
        log.warn(" !!server is dead ");
        if (this.serverUrl.equals(REMOTE_URL)) {
          DefaultApiGuideClient local = getDefaultApiGuideClientLocal();

          return local.execute(request, userId, sessionKey);
        } else {
          return null;
        }

      } catch (ApiException e1) {
        throw new ApiClientException(e1);
      }
    }
    log.warn(" serber alive " + serverUrl);
    String appkey = "12442245";

    Map<String, Object> rt = null;

    T tRsp = null;
    try {
      rt = doPost(request, appkey, userId, sessionKey, "common");
      if (rt == null)
        return null;
      tRsp = JSON.parseObject((String) rt.get("rsp"), request.getResponseClass());
      // tRsp = JsonUtil.toObject((String) rt.get("rsp"),
      // request.getResponseClass());
      tRsp.setBody((String) rt.get("rsp"));
      if (tRsp != null) {
        if (!tRsp.isSuccess()) {
          throw new ApiClientException(tRsp.getErrorCode(), tRsp.getMsg(), tRsp.getSubCode(), tRsp.getSubMsg());
        }
      }
    } catch (IOException e) {
      log.error("IOException get api client ", e);

      servelDeadNums.incrementAndGet();
      try {
        return this.getFromTaobao(request, sessionKey, app);
      } catch (ApiException e1) {
        throw new ApiClientException(e1);
      }
    } catch (Exception e) {
      log.error("error get api client ", e);
      if (rt != null)
        log.error("resp:" + (String) rt.get("rsp"));
      servelDeadNums.incrementAndGet();
      try {
        return this.getFromTaobao(request, sessionKey, app);
      } catch (ApiException e1) {
        throw new ApiClientException(e1);
      }
    }

    return tRsp;
  }

  public <T extends TaobaoResponse> T executeTbsmt(TaobaoRequest<T> request, Long userId, String sessionKey) throws ApiClientException {
    try {
      return this.getFromTaobao(request, sessionKey, APP.HD2);
    } catch (ApiException e1) {
      throw new ApiClientException(e1);
    }

  }

  public boolean registerUser(String appkey, Long userId, String nick, String moblile, String avatar, String sessionKey, String refreshToken, String shopName,
      Integer level, Integer version, Integer status, Long deadline) throws ApiClientException {
    if (appkey == null || userId == null || sessionKey == null) {
      throw new ApiClientException("appkey userId sessionkey must not be null!");
    }
    Map<String, String> params = new HashMap<String, String>();
    if (appkey != null) {
      params.put("appkey", appkey);
    }
    if (userId != null) {
      params.put("userId", userId + "");
    }
    if (nick != null) {
      params.put("nick", nick);
    }
    if (moblile != null) {
      params.put("moblile", moblile);
    }
    if (avatar != null) {
      params.put("avatar", avatar);
    }
    if (sessionKey != null) {
      params.put("sessionKey", sessionKey);
    }
    if (refreshToken != null) {
      params.put("refreshToken", refreshToken);
    }
    if (shopName != null) {
      params.put("shopName", shopName);
    }
    if (level != null) {
      params.put("level", level + "");
    }
    if (version != null) {
      params.put("version", version + "");
    }
    if (appkey != null) {
      params.put("status", status + "");
    }
    if (deadline != null) {
      params.put("deadline", deadline + "");
    }
    try {
      String rsp = WebUtils.doPost(this.registerUrl, params, Constants.CHARSET_UTF8, connectTimeout, readTimeout);
      return rsp != null && rsp.indexOf("success") > 0;
    } catch (IOException e) {
      throw new ApiClientException("error ", e);
    }
  }

  private static void convertServerDeadInfo() {
    long current = System.currentTimeMillis();
    if (!serverDead) {
      int num = servelDeadNums.get();
      if (num >= SERVEL_DEAD_NUM_LIMIT) {
        serverDead = true;
        servelDeadTime = current;
      } else {
        if (num > 0) {
          Random r = new Random();
          int i = r.nextInt(100);
          if (i <= 20) {
            servelDeadNums.decrementAndGet();
          }

        }
      }

    } else {

      if ((current - servelDeadTime) >= SERVEL_DEAD_TIME_LIMIT) {
        serverDead = false;
        servelDeadNums = new AtomicInteger(0);
      }
    }
  }

  public <T extends TaobaoResponse> Map<String, Object> doPost(TaobaoRequest<T> request, String appkey, Long userId, String sessionKey, String cmd)
      throws ApiClientException, IOException {
    Map<String, Object> result = new HashMap<String, Object>();

    Map<String, String> params = new HashMap<String, String>();
    List<NameValuePair> pars = new ArrayList<NameValuePair>();
    pars.add(new NameValuePair(ClientUrlParams.SESSIONKEY, sessionKey));
    if (userId != null)
      pars.add(new NameValuePair(ClientUrlParams.USER_ID, userId + ""));
    pars.add(new NameValuePair(ClientUrlParams.APP_KEY, appkey));
    pars.add(new NameValuePair(ClientUrlParams.REQUEST_CLASS, request.getClass().getName()));
    if (cmd != null)
      pars.add(new NameValuePair(ClientUrlParams.CMD, cmd));

    String requestStr = JSON.toJSONString(request);
    // String requestStr = JsonUtil.getJson(request);
    pars.add(new NameValuePair(ClientUrlParams.REQUEST, requestStr));

    String rsp = null;

    for (NameValuePair p : pars) {
      params.put(p.getName(), p.getValue());
    }
    // rsp = WebUtil.post(this.serverUrl, pars, connectTimeout,
    // readTimeout);
    rsp = WebUtils.doPost(this.serverUrl, params, Constants.CHARSET_UTF8, connectTimeout, readTimeout);

    result.put("rsp", rsp);
    result.put("params", pars);
    result.put("url", this.serverUrl);
    return result;
  }

  private <T extends TaobaoResponse> T getFromTaobao(TaobaoRequest<T> request, String sessionKey, APP app) throws ApiException {
    TaobaoClient client = genClient(app);

    return client.execute(request, sessionKey);

  }

  public String getServerUrl() {
    return serverUrl;
  }

  public void setServerUrl(String serverUrl) {
    this.serverUrl = serverUrl;
  }

  public String getRegisterUrl() {
    return registerUrl;
  }

  public void setRegisterUrl(String registerUrl) {
    this.registerUrl = registerUrl;
  }

  public int getConnectTimeout() {
    return connectTimeout;
  }

  public void setConnectTimeout(int connectTimeout) {
    this.connectTimeout = connectTimeout;
  }

  public int getReadTimeout() {
    return readTimeout;
  }

  public void setReadTimeout(int readTimeout) {
    this.readTimeout = readTimeout;
  }

  public static TaobaoClient genClient(APP app) {
    return new DefaultTaobaoClient(ApiConfigs.API_TAOBAO_URL, app.getAppkey(), app.getAppkeySec());
  }

  public static TaobaoClient genAutoRetryClient(APP app) {
    return new AutoRetryTaobaoClient(ApiConfigs.API_TAOBAO_URL, app.getAppkey(), app.getAppkeySec());
  }

  public static DefaultApiGuideClient getDefaultApiGuideClientLocal() {
    return new DefaultApiGuideClient(LOCAL_URL);
  }

  public static DefaultApiGuideClient getDefaultApiGuideClient() {
    return new DefaultApiGuideClient(REMOTE_URL);
  }

  public static void main(String[] args) {
    DefaultApiGuideClient client = DefaultApiGuideClient.getDefaultApiGuideClient();

    ItemGetRequest itemGet = new ItemGetRequest();
    itemGet.setNumIid(19583437464l);
    itemGet.setFields("numid,title,price,desc");
    for (int i = 0; i < 100; i++) {
      try {
        ItemGetResponse ires = client.execute(itemGet, null, null);
        if (ires != null && ires.getItem() != null)
          System.out.println(ires.getItem().getTitle());
      } catch (ApiClientException e2) {
        // TODO Auto-generated catch block
        e2.printStackTrace();
      }
    }

  }

}
